package com.ftp.longdistance.ftpmapper;

import cn.hutool.core.io.IoUtil;
import com.ftp.longdistance.annotation.FileType;
import com.ftp.longdistance.bean.Ftp;
import com.ftp.longdistance.exception.BizException;
import com.ftp.longdistance.ftpmapper.service.PointOfJunction;
import com.ftp.longdistance.util.FileViewUtils;
import com.ftp.longdistance.util.PathUtils;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author TanYongPeng
 * <p>
 *     Sftp模式
 * </p>
 */
@FileType(value = "SFTP")
@Slf4j
public enum SftpFile implements PointOfJunction {
    /**
     * 当前类自己
     * 通过枚举来实现单例模式，不仅避免多线程同步问题，
     * 而且还能防止反序列化创建新的对象
     */
    INSTANCE;

    private static ChannelSftp sftp = null;


    @Override
    public boolean getConnect(Ftp ftp){
        try {
            JSch jsch = new JSch();
            //获取sshSession  账号-ip-端口
            Session sshSession = jsch.getSession(ftp.getUserName(), ftp.getFtpHost(),ftp.getPort());
            //添加密码
            sshSession.setPassword(ftp.getPwd());
            sshSession.setTimeout(ftp.getTimedOut());
            Properties sshConfig = new Properties();
            //严格主机密钥检查
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            //开启sshSession链接
            sshSession.connect();
            //获取sftp通道
            Channel channel = sshSession.openChannel("sftp");
            //开启
            channel.connect();
            sftp = (ChannelSftp) channel;

            return true;
        } catch (Exception e) {
           return false;
        }
    }

    /**
     * 文件上传
     * @param path
     * @param file
     * @throws JSchException
     */
    @Override
    public void upload(String path, MultipartFile file){
        try {
            sftp.cd(path);
            sftp.put(file.getInputStream(), file.getOriginalFilename());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    /**
     * 创建文件夹
     * @param path
     */
    @Override
    public void dir(String path){
        try {
            sftp.mkdir(path);
        } catch (SftpException e) {
            throw new BizException("105","-bash: "+path+": command execution failure  文件创建失败");
        }
    }

    /**
     * 删除文件夹
     * @param path
     */
    @Override
    public void deleteDir(String path){
        try {
            sftp.rmdir(path);
        } catch (SftpException e) {
            throw new BizException("105","-bash: "+path+": command execution failure  文件夹删除失败");
        }
    }

    /**
     * 下载文件
     *
     */
    @Override
    public void download(String serverPath,String fileName) {
        try {
            sftp.cd(serverPath);
            String fileStr = PathUtils.viewPath(fileName);
            File file = new File(fileStr);
            if (file.exists()) {
                fileName = "("+System.currentTimeMillis()+")"+fileName;
                File file2 = new File(PathUtils.viewPath(fileName));
                download(fileName,file2);
            }else {
                download(fileName,file);
            }
        } catch (Exception e) {
            throw new BizException("103","文件下载异常");
        }
    }

    @Override
    public void fileView(HttpServletResponse response, String path, String fileName) {
        try {
            sftp.cd(path);
            String fileStr = PathUtils.fileViewPath(fileName);
            File file = new File(fileStr);
            if (file.exists()){
                file.delete();
            }
            download(fileName,file);
            FileViewUtils.fileView(response,file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void download(String fileName,File file) throws IOException, SftpException {
        InputStream extInputStream = sftp.getExtInputStream();
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        sftp.get(fileName,fileOutputStream);
        IoUtil.close(extInputStream);
        IoUtil.close(fileOutputStream);
    }

    @Override
    public boolean checkExist(String filePath){
        return checkFileName(filePath);
    }

    @Override
    public boolean checkFileName(String filePath){
        try{
            sftp.cd(filePath);
            sftp.cd("..");
            return true;
        }catch (Exception e){
            return false;
        }
    }



    /**
     * 删除文件
     *
     */
    @Override
    public void delete(String servicePath,String fileName) {
        try {
            sftp.cd(servicePath);
            sftp.rm(fileName);
        } catch (Exception e) {
            throw new BizException("104","文件删除异常");
        }
    }

    /**
     * 关闭sftp连接
     */
    @Override
    public void logout(){
        if (sftp != null) {
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
        }
        try {
            if (sftp.getSession() != null) {
                if (sftp.getSession().isConnected()) {
                    sftp.getSession().disconnect();
                }
            }
        } catch (Exception e) {
                e.printStackTrace();
        }
    }

    /**
     * 列出目录下的文件
     *
     * @param directory
     *            要列出的目录
     * @return
     * @throws SftpException
     */
    @Override
    public List<String> listFiles(String directory){
        List<String> list = new ArrayList<>();
        try {
            directory = PathUtils.checkPath(directory);
            log.info("directory = {}",directory);
            Vector vector = sftp.ls(directory);
            log.info("vector = {}",vector);
            for (int i = 0; i < vector.size(); i++) {
                String[] split = vector.get(i).toString().split(" ");
                String str = split[split.length - 1];
                list.add(str.trim());
                list.removeIf(l -> l.equals(".") || l.equals(".."));
            }
        }catch (Exception e){
            throw new BizException("101","文件路径异常");
        }
        return list;
    }


    /**
     * 更改名称
     * @param oldPath
     * @param newPath
     */
    @Override
    public void rename(String oldPath,String newPath){
        try {
            sftp.rename(oldPath,newPath);
        } catch (SftpException e) {
            throw new BizException("107","文件名更改异常");
        }
    }

    /**
     * 获取文件权限
     * @param path
     * @return
     */
    @Override
    public String fileAuthority(String path){
        return sizeAndAuthority(path)[0];
    }

    /**
     * 获取文件大小
     * @param path
     * @return
     */
    @Override
    public String fileSize(String path){
        return sizeAndAuthority(path)[1];
    }




    /**
     * 返回文件大小和文件权限
     * @param path
     * @return
     */
    public String[] sizeAndAuthority(String path){
        String[] array = new String[2];
        try {
            Vector ls = sftp.ls(path);
            String[] split = ls.get(0).toString().split(" ");
            List<String> collect = Arrays.stream(split).collect(Collectors.toList());
            collect.removeIf(l -> l.equals("") || l.equals(" ") || l == null);
            array[0] = collect.get(0).trim();
            array[1] = collect.get(4).trim();
        } catch (SftpException e) {
            throw new BizException();
        }
        return array;
    }
}
